/*
 * Serial.cpp
 *
 *  Created on: 2011-12-20
 *      Author: kaishui
 */

#include "Serial.h"


bool Serial::Open(char* ser)
{

	m_fd=open(ser,O_RDWR);
	if(-1 == m_fd)
	{
		perror("Can't Open Serial Port!\n");
		return false;
	}
	if(flock(m_fd,LOCK_EX)<0)
	{
		perror(" Serial Port is already open!\n");
		return false;
	}
	return true;
}

void Serial::Close()
{
	flock(m_fd,LOCK_UN);
	close(m_fd);
}



int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {115200,38400, 19200, 9600, 4800, 2400, 1200, 300, };

bool Serial::SetParity(int speed,int parity,int databits,int stopbits)
{
	unsigned int i;
	int status;
	struct termios options;
	if (tcgetattr(m_fd,&options) != 0)
	{
		perror("SetupSerial 1");
		return  false;
	}
	for ( i= 0; i < (sizeof(speed_arr) / sizeof(int)); i++)
	{
		if (speed == name_arr[i])
		{
			tcflush(m_fd, TCIOFLUSH);
			cfsetispeed(&options, speed_arr[i]);
			cfsetospeed(&options, speed_arr[i]);
			status = tcsetattr(m_fd, TCSANOW, &options);
			if (status != 0)
			{
				perror("tcsetattr fd");
				return false;
			}
			tcflush(m_fd,TCIOFLUSH);
		}
	}


		options.c_cflag &= ~CSIZE;
		switch (databits) /*设置数据位数*/
		{
			case 7:
				options.c_cflag |= CS7;
				break;
			case 8:
				options.c_cflag |= CS8;
				break;
			default:
				fprintf(stderr,"Unsupported data sizen");
				return false;
		}
		switch (parity)
		{
			case 'n':
			case 'N':
				options.c_cflag &= ~PARENB; /* Clear parity enable */
				options.c_iflag &= ~INPCK; /* Enable parity checking */
				break;
			case 'o':
			case 'O':
				options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
				options.c_iflag |= INPCK; /* Disnable parity checking */
				break;
			case 'e':
			case 'E':
				options.c_cflag |= PARENB; /* Enable parity */
				options.c_cflag &= ~PARODD; /* 转换为偶效验*/
				options.c_iflag |= INPCK; /* Disnable parity checking */
				break;
			case 'S':
			case 's': /*as no parity*/
				options.c_cflag &= ~PARENB;
				options.c_cflag &= ~CSTOPB;break;
			default:
				fprintf(stderr,"Unsupported parityn");
				return false;
		}
		/* 设置停止位*/
		switch (stopbits)
		{
			case 1:
				options.c_cflag &= ~CSTOPB;
				break;
			case 2:
				options.c_cflag |= CSTOPB;
				break;
			default:
				fprintf(stderr,"Unsupported stop bitsn");
				return false;
		}

		options.c_cflag &= ~CRTSCTS;
	//	options.c_iflag &= ~IXOFF;
	//	options.c_iflag &= ~IXON;
		options.c_iflag=0;    //0x0d 读成0x0a,所以必须c_iflag设成0

		/* Set input parity option */
		if (parity != 'n')
			options.c_iflag |= INPCK;
		options.c_lflag&=~(ICANON|ECHO|ECHOE|ISIG);
		options.c_oflag&=~OPOST;
		tcflush(m_fd,TCIFLUSH);
		options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/
		options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
		if (tcsetattr(m_fd,TCSANOW,&options) != 0)
		{
			perror("SetupSerial 3");
			return false;
		}
		return true;
}


int Serial::Read(char* buf,int len,double timeout)
{
	 int nread=-1;
	 int ret;
	 fd_set readfds;
	 struct timeval tv;
	 tv.tv_sec=int(timeout);
	 tv.tv_usec=(timeout-int(timeout))*1000000;
	 FD_ZERO(&readfds);
	 FD_SET(m_fd,&readfds);

	 if(timeout<0)  //不设置超时时间
	 {
		 ret=select(m_fd+1,&readfds,NULL,NULL,0);
	 }
	 else
		 ret=select(m_fd+1,&readfds,NULL,NULL,&tv);

	if (ret == -1)
	{
		printf("Serial recv select error.\n");
		return -1;
	}
	else if (ret == 0)
	{

		printf("Serial recv select timeout.\n");
		return -2;
	}
	 if(!FD_ISSET(m_fd,&readfds))
	 {
		 printf("Serial recv select not from m_fd\n");
		 return -3;
	 }
	 usleep(100000);
	 nread=read(m_fd,(void *)buf,len);
	 return nread;
}


int Serial::Write(char* buf,int len)
{
	int nwrite=-1;
	nwrite=write(m_fd,(void*)buf,len);
	return nwrite;
}
